﻿using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Serialization;
using UnityEngine.UI;

namespace EG
{
    public class UIPage : MonoBehaviour
    {
        #region static

        private static bool isInit;
        public static GameObject root;
        public static GameObject normalNode;
        public static GameObject fixedNode;
        public static GameObject popupNode;
        public static Camera uiCamera;
        //public static AudioListener uiAudioListener;
        public static EventSystem eventSystem;
        public static Canvas canvas;
        public static CanvasScaler canvasScaler;
        public static GraphicRaycaster graphicRaycaster;
        public static float screenWidth = 1080;
        public static float screenHeight = 1920;
        private static bool isPortrait;
        public static AllPages allPages;

        #endregion

        #region member

        public string uiPath;
        public string pageName;
        public UIType uiType;
        public UIData uiData;

        #endregion


        private static void Init()
        {
            root = new GameObject("Root");
            DontDestroyOnLoad(root);
            root.transform.position = Vector3.zero;
            normalNode = new GameObject("NormalNode");
            normalNode.transform.SetParent(root.transform);
            normalNode.transform.localPosition = Vector3.zero;
            fixedNode = new GameObject("FixedNode");
            fixedNode.transform.SetParent(root.transform);
            fixedNode.transform.localPosition = Vector3.zero;
            popupNode = new GameObject("PopupNode");
            popupNode.transform.SetParent(root.transform);
            popupNode.transform.localPosition = Vector3.zero;
            uiCamera = new GameObject("UICamera").AddComponent<Camera>();
            uiCamera.transform.SetParent(root.transform);
            uiCamera.transform.localPosition = Vector3.zero;
            eventSystem = new GameObject("EventSystem").AddComponent<EventSystem>();
            eventSystem.transform.SetParent(root.transform);
            eventSystem.transform.localPosition = Vector3.zero;

            canvas = root.AddComponent<Canvas>();
            canvasScaler = root.AddComponent<CanvasScaler>();
            canvasScaler.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize;
            graphicRaycaster = root.AddComponent<GraphicRaycaster>();

            //uiAudioListener = uiCamera.gameObject.AddComponent<AudioListener>();
            uiCamera.clearFlags = CameraClearFlags.Depth;
            uiCamera.cullingMask = 1 << LayerMask.NameToLayer("UI");
            // //相机打开Defalut层
            // uiCamera.cullingMask |= (1 << 0);
            //
            uiCamera.orthographic = true;
            uiCamera.transform.localPosition = Vector3.back * 1500;
            canvas.renderMode = RenderMode.ScreenSpaceCamera;
            canvas.worldCamera = uiCamera;

            RectTransform nrf = normalNode.AddComponent<RectTransform>();
            RectTransform frf = fixedNode.AddComponent<RectTransform>();
            RectTransform prf = popupNode.AddComponent<RectTransform>();

            nrf.sizeDelta = new Vector2(screenWidth, screenHeight);
            frf.sizeDelta = new Vector2(screenWidth, screenHeight);
            prf.sizeDelta = new Vector2(screenWidth, screenHeight);

            root.layer = LayerMask.NameToLayer("UI");
            normalNode.layer = LayerMask.NameToLayer("UI");
            fixedNode.layer = LayerMask.NameToLayer("UI");
            popupNode.layer = LayerMask.NameToLayer("UI");

            eventSystem.gameObject.AddComponent<StandaloneInputModule>();

            allPages = new AllPages();

            isPortrait = screenWidth < screenHeight;

            if (isPortrait)
            {
                ChangeToPortrait();
            }
            else
            {
                ChangeToLandscape();
            }

            isInit = true;
        }

        public static T ShowPage<T>(UIData data = null) where T : UIPage, new()
        {
            if (!isInit)
            {
                Init();
            }

            T t = new T();

            if (allPages.ContainsKey(typeof(T).ToString()))
            {
                T pg = (T) allPages[typeof(T).ToString()];
                pg.uiData = data;
                pg.OnShowPage();

                UIPage curPage = allPages.GetCurPage(pg.uiType);
                if (curPage != null && curPage != pg)
                {
                    curPage.OnLostFocusPage();
                }

                allPages.SetAsLastSibling(pg.pageName);
                if (!pg.gameObject.activeSelf)
                {
                    pg.OnActive();
                }

                return pg;
            }

            t.InitPage();
            GameObject prefab = Resources.Load<GameObject>(t.uiPath);
            T page = Instantiate(prefab).AddComponent<T>();
            page.InitPage();
            page.name = typeof(T).ToString();
            page.pageName = typeof(T).ToString();
            allPages.AddPage(page);
            page.uiData = data;
            
            #region MyRegion

            RectTransform rectTransform = page.GetComponent<RectTransform>();
            Vector3 anchorPos = Vector3.zero;
            
            Vector3 scale = Vector3.one;
            Vector2 sizeDel = Vector2.zero;
            if (rectTransform != null)
            {
                anchorPos = rectTransform.anchoredPosition;
                scale = rectTransform.localScale;
                sizeDel = rectTransform.sizeDelta;
            }
            else
            {
                scale = page.transform.localScale;
            }


            if (page.uiType == UIType.Normal)
            {
                page.transform.SetParent(normalNode.transform);
            }
            else if (page.uiType == UIType.Fixed)
            {
                page.transform.SetParent(fixedNode.transform);
            }
            else if (page.uiType == UIType.PopUp)
            {
                page.transform.SetParent(popupNode.transform);
            }

            if (rectTransform != null)
            {
                rectTransform.anchoredPosition = anchorPos;
                rectTransform.localScale = scale;
                rectTransform.sizeDelta = sizeDel;
            }
            else
            {
                page.transform.localScale = scale;
                page.transform.localPosition = Vector3.zero;
            }

            #endregion
            
            page.OnShowPage();

            UIPage curPage2 = allPages.GetCurPage(page.uiType);
            if (curPage2 != null && curPage2 != page)
            {
                curPage2.OnLostFocusPage();
            }

           
            

            page.OnActive();
            return page;
        }

        public static void ClosePage<T>() where T : UIPage, new()
        {
            if (!isInit)
            {
                Init();
            }

            T t = new T();
            t.InitPage();
            if (allPages.ContainsKey(typeof(T).ToString()))
            {
                T pg = (T) allPages[typeof(T).ToString()];
                pg.OnClosePage();
                if (pg.gameObject.activeSelf)
                {
                    pg.OnHide();
                }

                UIPage curPage = allPages.GetCurPage(pg.uiType);
                if (curPage != null && curPage != pg)
                {
                    curPage.OnFocusPage();
                }
            }
            else
            {
                Debug.LogWarning("no page named \"" + typeof(T) + "\"");
            }
        }

        public static void CloseCurPage(UIType uiType)
        {
            UIPage page = allPages.GetCurPage(uiType);
            if (page != null)
            {
                if (!isInit)
                {
                    Init();
                }

                page.OnClosePage();
                if (page.gameObject.activeSelf)
                {
                    page.OnHide();
                }

                UIPage curPage = allPages.GetCurPage(page.uiType);
                if (curPage != null && curPage != page)
                {
                    curPage.OnFocusPage();
                }
            }
        }

        public static void ChangeToLandscape()
        {
            if (isPortrait)
            {
                canvasScaler.referenceResolution = new Vector2(screenHeight, screenWidth);
                canvasScaler.matchWidthOrHeight = 1;
                Screen.orientation = ScreenOrientation.LandscapeLeft;
            }
            else
            {
                canvasScaler.referenceResolution = new Vector2(screenWidth, screenHeight);
                canvasScaler.matchWidthOrHeight = 1;
                Screen.orientation = ScreenOrientation.LandscapeLeft;
            }
        }

        public static void ChangeToPortrait()
        {
            if (isPortrait)
            {
                canvasScaler.referenceResolution = new Vector2(screenWidth, screenHeight);
                canvasScaler.matchWidthOrHeight = 0;
                Screen.orientation = ScreenOrientation.Portrait;
            }
            else
            {
                canvasScaler.referenceResolution = new Vector2(screenHeight, screenWidth);
                canvasScaler.matchWidthOrHeight = 0;
                Screen.orientation = ScreenOrientation.Portrait;
            }
        }

        public virtual void InitPage()
        {
        }

        public virtual void OnShowPage()
        {
        }

        public virtual void OnClosePage()
        {
        }

        public virtual void OnFocusPage()
        {
        }

        public virtual void OnLostFocusPage()
        {
        }

        public virtual void OnActive()
        {
            gameObject.SetActive(true);
        }

        public virtual void OnHide()
        {
            gameObject.SetActive(false);
        }

        public bool IsOnGUI
        {
            get
            {
                PointerEventData eventData = new PointerEventData(EventSystem.current);
                eventData.pressPosition = Input.mousePosition;
                eventData.position = Input.mousePosition;

                List<RaycastResult> list = new List<RaycastResult>();
                graphicRaycaster.Raycast(eventData, list);
                return list.Count > 0;
            }
        }
    }

    public enum UIType
    {
        Normal,
        Fixed,
        PopUp,
        None,
    }

    public class AllPages
    {
        private List<UIPage> allPages;

        public UIPage this[int index]
        {
            get { return allPages[index]; }
        }

        public UIPage this[string pageName]
        {
            get
            {
                foreach (var uiPage in allPages)
                {
                    if (uiPage.pageName == pageName)
                    {
                        return uiPage;
                    }
                }

                throw new KeyNotFoundException("the ui which has a name called \"" + pageName + "\" can not be found!");
            }
        }

        public void AddPage(UIPage page)
        {
            if (allPages == null)
            {
                allPages = new List<UIPage>();
            }

            foreach (var uiPage in allPages)
            {
                if (uiPage.pageName == page.pageName)
                {
                    throw new Exception("has already add a page which called \"" + page.pageName + "\"!");
                }
            }

            allPages.Add(page);
        }

        public bool ContainsKey(string pageName)
        {
            if (allPages == null)
            {
                allPages = new List<UIPage>();
            }

            foreach (var uiPage in allPages)
            {
                if (uiPage.pageName == pageName)
                {
                    return true;
                }
            }

            return false;
        }

        public void SetAsLastSibling(string pageName)
        {
            var temp = this[pageName];
            allPages.Remove(this[pageName]);
            this.AddPage(temp);
            temp.transform.SetAsLastSibling();
        }

        public UIPage GetCurPage(UIType uiType)
        {
            for (int i = allPages.Count - 1; i >= 0; i--)
            {
                if (allPages[i].gameObject.activeSelf && allPages[i].uiType == uiType)
                {
                    return allPages[i];
                }
            }

            return null;
        }
    }

    public class UIData
    {
        public object data;
        public Action cb;
    }
}